<template>
  <div class="header">
    <div class="left">
      <i class="iconfont icon-mine"></i>
      <span>{{ mineNum - mineMarkNum }}</span>
    </div>
    <div class="title">第{{ mineLevel + 1 }}关</div>
    <div class="right" @click="init">重新开始</div>
  </div>
  <div class="mine-wrap" :style="mineWrapStyle">
    <div
      class="mine-item"
      v-for="(mine, i) in mineList"
      :key="i"
      :style="mineStyle(mine)"
      @click="clickLeft(mine)"
      @contextmenu.prevent="clickRight(mine)"
    >
      <template v-if="mine.show && mine.value">
        {{ mine.value }}
      </template>
    </div>
  </div>
</template>
<script setup lang="ts">
import { ref, computed, watch } from "vue";
const around = [
  [-1, -1],
  [0, -1],
  [1, -1],
  [-1, 0],
  [1, 0],
  [-1, 1],
  [0, 1],
  [1, 1],
];
interface Mine {
  type: string;
  x: number;
  y: number;
  value: number;
  show: Boolean;
  mark: Boolean;
}
const mineLevels = ref([
  [9, 9, 10],
  [16, 16, 40],
  [20, 20, 80],
  [20, 20, 100],
  [20, 25, 150],
  [20, 25, 200],
  [20, 25, 250],
]);
const mineLevel = ref(0);
const GameOver = ref(false);
const mineRow = computed(() => {
  return mineLevels.value[mineLevel.value][1];
});
const mineColumn = computed(() => {
  return mineLevels.value[mineLevel.value][0];
});
const mineNum = computed(() => {
  return mineLevels.value[mineLevel.value][2];
});
const mineMarkNum = ref(0);
const showNum = ref(0);
const mineList: any = ref([]);

watch(showNum, (val) => {
  if (
    !GameOver.value &&
    val === mineRow.value * mineColumn.value - mineNum.value
  ) {
    alert("恭喜过关，继续下一关");
    ++mineLevel.value;
  }
});
watch(mineLevel, (val) => {
  if (val > mineLevels.value.length) {
    alert("已全部通关");
  } else {
    init();
  }
});
const mineWrapStyle = computed(() => {
  let w = 100 / mineColumn.value;
  return {
    gridTemplateRows: `repeat(${mineRow.value}, ${w}vmin)`,
    gridTemplateColumns: `repeat(${mineColumn.value}, ${w}vmin)`,
  };
});
const mineStyle = computed(() => (mine: Mine) => {
  let colors = [
    "#0332fe",
    "#019f02",
    "#ff2600",
    "#93208f",
    "#ff7f29",
    "#ff3fff",
    "#3fffbf",
    "#22ee0f",
  ];
  let backgroundImage = "";
  if (mine.mark) {
    backgroundImage = `url('./mark.png')`;
  }
  if (mine.show && mine.type === "mine") {
    backgroundImage = `url('./mine.png')`;
  }
  return {
    background: mine.show ? "#fff" : "#ccc",
    backgroundImage,
    color: mine.show && mine.type === "number" ? colors[mine.value - 1] : "",
  };
});

const init = () => {
  GameOver.value = false;
  showNum.value = 0;
  mineMarkNum.value = 0;
  //随机生成雷的位置
  const minePos = Array.from({ length: mineRow.value * mineColumn.value })
    .map((e, i) => i)
    .sort((e) => 0.5 - Math.random())
    .splice(0, mineNum.value);
  //生成列表
  /*row = 3    column = 4   
    0   1   2   3    [0,0] [1,0] [2,0] [3,0]
    4   5   6   7    [0,1] [1,1] [2,1] [3,1]
    8   9   10  11   [0,2] [1,2] [2,2] [3,2]
    12  13  14  15   [0,3] [1,3] [2,3] [3,3]
    16  17  18  19   [0,4] [1,4] [2,4] [3,4]    
    x = i % column   y = Math.floor(i / column)   i = y * column + x
  */
  mineList.value = Array.from({
    length: mineRow.value * mineColumn.value,
  }).map((e, i) => {
    let x = i % mineColumn.value;
    let y = Math.floor(i / mineColumn.value);
    return {
      type: minePos.includes(i) ? "mine" : "number",
      x,
      y,
      value: 0,
      show: false,
      mark: false,
    };
  });
  //更新数字
  mineList.value.map((e: Mine) => {
    if (e.type === "mine") return;
    const nums = around.map((xy) => {
      let item: any = mineList.value.find((l: Mine) => {
        return l.x === e.x + xy[0] && l.y === e.y + xy[1];
      });
      return item?.type === "mine" ? 1 : 0;
    });
    e.value = nums.reduce((prev: number, cur: number) => prev + cur, 0);
  });
};
init();

const clearZero = (mine: Mine) => {
  around.map((xy) => {
    let item = mineList.value.find((m: Mine) => {
      return m.x === mine.x + xy[0] && m.y === mine.y + xy[1];
    });
    if (
      item?.type === "number" &&
      item?.show === false &&
      item?.mark === false
    ) {
      item.show = true;
      ++showNum.value;
      if (item.value === 0) {
        clearZero(item);
      }
    }
  });
};
const gameOver = () => {
  GameOver.value = true;
  mineList.value.map((mine: Mine) => {
    if (mine.mark && mine.type === "mine") return;
    mine.show = true;
  });
  alert("失败");
};
const clickLeft = (mine: Mine) => {
  if (GameOver.value || mine.show || mine.mark) return;
  if (mine.type === "number") {
    mine.show = true;
    ++showNum.value;
    if (mine.value === 0) {
      clearZero(mine);
    }
  } else {
    mine.show = true;
    gameOver();
  }
};
const clickRight = (mine: Mine) => {
  if (mine.show) return;
  mine.mark = !mine.mark;
  mineMarkNum.value = mine.mark ? ++mineMarkNum.value : --mineMarkNum.value;
  if (mineMarkNum.value === mineNum.value) {
    let markMine = mineList.value.filter((e: Mine) => e.mark);
    if (markMine.every((e: Mine) => e.type === "mine")) {
      alert("恭喜过关，继续下一关");
      ++mineLevel.value;
    } else {
      gameOver();
    }
  }
};
</script>

<style>
* {
  padding: 0;
  margin: 0;
}
::-webkit-scrollbar {
  /* display: none; */
}
body {
  background: #f1f3f5;
}
#app {
  max-width: 100vmin;
  margin: 0 auto;
  background: #fff;
}
.header {
  position: sticky;
  top: 0;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0px 4vmin;
  height: 10vmin;
  background: #fff;
  border-bottom: 1px solid #ccc;
}
.mine-wrap {
  display: grid;
}
.mine-item {
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px solid;
  background: #ccc;
  border-color: #fff #a1a1a1 #a1a1a1 #fff;
  background-size: 100% !important;
  overflow: hidden;
}
</style>
